package com.sjz.MulThreadDownloader;

import java.io.File;

import com.sjz.net.DownloadProgressListener;
import com.sjz.net.FileDownloader;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

/****
 * 多线程断点下载文件 
 */
public class MulThreadDownloaderActivity extends Activity {
	    private EditText pathText;   //下载路径
	    private TextView resultView;   //进度条的内容
	    private Button downloadButton; //下载按钮
	    private Button stopbutton;  //暂停按钮
	    private ProgressBar progressBar;  //进度条对象
	    /*****
	     * hanlder的作用是用于往创建Hander对象所在的线程所绑定的消息队列发送消息
	     */
	    private Handler handler = new UIHander(); 
	    
	    
	    /*****
	     * 这个是重写handler类     把子线程的消息在主线程上来实现
	     *
	     */
	   private final class UIHander extends Handler{
		   //子线程  handler.sendMessage(msg);  发送的内容  会在这里来进行处理  DownloadTask类的run方法
		   //这是在主线程执行的
			public void handleMessage(Message msg) {
				switch (msg.what) {  //msg.what 得到下载成功或者失败的标识
				case 1: //下载成功
					int size = msg.getData().getInt("size");  //得到上传的大小
					progressBar.setProgress(size);//设置当前的进度
					float num = (float)progressBar.getProgress() / (float)progressBar.getMax(); //得到当前的进度占总大小的百分比
					int result = (int)(num * 100);//转换成百分比
					resultView.setText(result+ "%"); //设置进去 来进行展示
					if(progressBar.getProgress() == progressBar.getMax()){  //如果是最大的话，提示成功
						Toast.makeText(getApplicationContext(), R.string.success, 1).show();
					}
					break;

				case -1:  //下载失败  
					Toast.makeText(getApplicationContext(), R.string.error, 1).show();
					break;
				}
			}
	    }
	    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        pathText = (EditText) this.findViewById(R.id.path);
        resultView = (TextView) this.findViewById(R.id.resultView);
        downloadButton = (Button) this.findViewById(R.id.downloadbutton);
        stopbutton = (Button) this.findViewById(R.id.stopbutton);
        progressBar = (ProgressBar) this.findViewById(R.id.progressBar);
        ButtonClickListener listener = new ButtonClickListener();
        downloadButton.setOnClickListener(listener);  //点击按钮 触发点击事件
        stopbutton.setOnClickListener(listener);
    }
    
    
    /*****
     * 点击事件触发的类
     */
    private final class ButtonClickListener implements View.OnClickListener{
		public void onClick(View v) {
			switch (v.getId()) {//通过判断id 来得到是下载还是停止的按钮来进行触发的
			case R.id.downloadbutton:    //下载按钮
				String path = pathText.getText().toString();//得到文件的路径 
				if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
					//判断sd卡是否存在   并且是否可以写数据Environment.MEDIA_MOUNTED(表示可以写数据)
					File saveDir = Environment.getExternalStorageDirectory(); 
					//Environment.getExternalStorageDirectory()   得到sd卡的根目录
					download(path, saveDir);
				}else{
					//提示sd卡不可以写数据
					Toast.makeText(getApplicationContext(), R.string.sdcarderror, 1).show();
				}
				downloadButton.setEnabled(false); //下载按钮设置成不可用
				stopbutton.setEnabled(true);//停止按钮设置成可用
				break;

			case R.id.stopbutton:   //停止按钮触发
				exit();
				downloadButton.setEnabled(true); //下载按钮 设置成 可用
				stopbutton.setEnabled(false);//停止按钮设置成不可用
				break;
			}
		}
		
		/*
		由于用户的输入事件(点击button, 触摸屏幕....)是由主线程负责处理的，如果主线程处于工作状态，
		此时用户产生的输入事件如果没能在5秒内得到处理，系统就会报“应用无响应”错误。
		所以在主线程里不能执行一件比较耗时的工作，否则会因主线程阻塞而无法处理用户的输入事件，
		导致“应用无响应”错误的出现。耗时的工作应该在子线程里执行。
		 */
		private DownloadTask task;
		
		
		/**
		 * 退出下载
		 */
		public void exit(){
			if(task!=null) task.exit();
		}
		
		
		/****
		 * 下载文件   使用的多线程来处理
		 * @param path   文件的下载路径
		 * @param saveDir   文件的保存路径 
		 * 由于用户的输入事件（点击button，触摸屏幕。。。）是由主线程负责处理的，如果主线程处于工作状态，此时用户产生的输入事件
		 * 如果没能在5s内得到处理，系统就会报"应用无响应"错误
		 * 所以在主线程里不能执行一件比较耗时的工作，否则会因主线程阻塞而无法处理用户的输入事件，
		 * 导致"应用无响应"的错误出现，耗时的工作应该在子线程中执行  !!!!!
		 */
		private void download(String path, File saveDir) {//运行在主线程   如果文件太大  导致主线程一致在运行 
			task = new DownloadTask(path, saveDir);  //使用多线程来进行下载
			new Thread(task).start();  //启动多线程
		}
		
		
		/*
		 * UI控件画面的重绘(更新)是由主线程负责处理的，如果在子线程中更新UI控件的值，更新后的值不会重绘到屏幕上
		 * 一定要在主线程里更新UI控件的值，这样才能在屏幕上显示出来，不能在子线程中更新UI控件的值  
		 *  这里使用hander往主线程发送消息 !!!!!
		 * 实现文件的下载
		 */
		private final class DownloadTask implements Runnable{
			private String path;
			private File saveDir;
			private FileDownloader loader;
			public DownloadTask(String path, File saveDir) {
				this.path = path;
				this.saveDir = saveDir;
			}
			/**
			 * 退出下载
			 */
			public void exit(){
				if(loader!=null) loader.exit();
			}
			
			public void run() {
				try {
					//创建多线程下载器  传入下载路径     保存路径   三条线程(安卓手机开太多线程不太好)
					loader = new FileDownloader(getApplicationContext(), path, saveDir, 3);
					progressBar.setMax(loader.getFileSize());//设置进度条的最大刻度   文件的大小 
					
					//设置监听  可以实时的得到下载的进度   使用的是内部类来实现下载
					loader.download(new DownloadProgressListener() { 
						
						public void onDownloadSize(int size) {
							Message msg = new Message();   //创建消息对象
							msg.what = 1;   //设置标识  如果为1  说明是成功的消息
							msg.getData().putInt("size", size);  //设置参数的内容
							handler.sendMessage(msg);  //发送消息对象  发送给主线程   主线程来进行UI绘图
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
					handler.sendMessage(handler.obtainMessage(-1));
					//发送失败消息   
					//handler.obtainMessage(-1) 表示创建一个消息  并且标识成失败的标识
				}
			}			
		}
    }
}